package com.orifine.dao.parser;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SelectAsParser {
	private String sql;
	private StringBuffer sqlBuff;

	private SelectAsParser(String sql) {
		this.sql = sql;
		this.sqlBuff = new StringBuffer(" ").append(sql).append(" ");

		this.stringParse();
		this.selectFromParse();
		this.asParse();
		this.selectFromUndo();
		this.stringUndo();
	}

	private Map<Integer[], String> stringParseMap = new LinkedHashMap<Integer[], String>();

	private void stringParse() {
		Matcher matcher = STRING_PATTERN.matcher(sqlBuff);

		int impo = 0;
		int impoPosition = 0;
		int offset = 0;
		for (int bufpos = 0; matcher.find(bufpos);) {
			if (matcher.group().equals("\'")) {
				if (impo == 0) {
					impo = 1;
					impoPosition = matcher.end();
				} else if (impo == 1) {
					impo = 0;
					stringParseMap.put(new Integer[] { impoPosition - offset, matcher.start() - offset }, null);
					offset += matcher.start() - impoPosition;
				}
			} else if (matcher.group().equals("\"")) {
				if (impo == 0) {
					impo = 2;
					impoPosition = matcher.end();
				} else if (impo == 2) {
					impo = 0;
					stringParseMap.put(new Integer[] { impoPosition - offset, matcher.start() - offset }, null);
					offset += matcher.start() - impoPosition;
				}
			}
			bufpos = matcher.end();
		}

		for (Integer[] del : stringParseMap.keySet()) {
			stringParseMap.put(del, sqlBuff.substring(del[0], del[1]));
			sqlBuff.replace(del[0], del[1], "");
		}
	}

	private void stringUndo() {
		int offset = 0;
		for (Integer[] del : stringParseMap.keySet()) {
			String value = stringParseMap.get(del);
			sqlBuff.insert(del[0] + offset, stringParseMap.get(del));
			offset = value.length();
		}
	}

	private Map<Integer[], StringBuffer> selectFromParseMap = new LinkedHashMap<Integer[], StringBuffer>();

	private void selectFromParse() {
		Matcher matcher = SELECT_FROM_PATTERN.matcher(sqlBuff);
		int impo = 0;
		int impoPosition = 0;
		int offset = 0;
		for (int bufpos = 0; matcher.find(bufpos);) {
			String groupValue = matcher.group(1).toUpperCase();
			if (groupValue.equals("SELECT") && impo == 0) {
				impo = 1;
				impoPosition = matcher.end();
			} else if (groupValue.equals("FROM") && impo == 1) {
				impo = 0;
				selectFromParseMap.put(new Integer[] { impoPosition - offset, matcher.start() - offset, impoPosition }, null);
				offset += matcher.start() - impoPosition;
			} else {
				throw new RuntimeException("ERROR:" + sql);
			}
			bufpos = matcher.end();
		}

		for (Integer[] del : selectFromParseMap.keySet()) {
			selectFromParseMap.put(del, new StringBuffer(sqlBuff.substring(del[0], del[1])));
			sqlBuff.replace(del[0], del[1], "");
		}
	}

	private void selectFromUndo() {
		int offset = 0;
		for (Integer[] del : selectFromParseMap.keySet()) {
			StringBuffer value = selectFromParseMap.get(del);
			sqlBuff.insert(del[0] + offset, selectFromParseMap.get(del));
			offset = value.length();
		}
	}

	private void asParse() {
		for (StringBuffer asBuffer : selectFromParseMap.values()) {
			Map<Integer[], String> asParseMap = new LinkedHashMap<Integer[], String>();
			Matcher matcher = AS_PATTERN.matcher(asBuffer);
			while (matcher.find()) {
				asParseMap.put(new Integer[] { matcher.end() - matcher.group(1).length(), matcher.end() }, "'" + matcher.group(1) + "'");
			}

			int offset = 0;
			for (Integer[] ins : asParseMap.keySet()) {
				String str = asParseMap.get(ins);
				asBuffer.delete(ins[0] + offset, ins[1] + offset);
				asBuffer.insert(ins[0] + offset, str);
				offset += str.length() - (ins[1] - ins[0]);
			}
		}
	}

	public String toString() {
		return sqlBuff.toString();
	}

	private static final Pattern STRING_PATTERN = Pattern.compile("(?:\\\\\\\\|\\\\\\'|\\\"|\\\'|\"|')", Pattern.CASE_INSENSITIVE);
	private static final Pattern SELECT_FROM_PATTERN = Pattern.compile("[^\\w\\.](select|from)[^\\w\\.]", Pattern.CASE_INSENSITIVE);
	private static final Pattern AS_PATTERN = Pattern.compile("as\\s+([\\w.]+)", Pattern.CASE_INSENSITIVE);

	public static String parse(String querySql){
		return new SelectAsParser(querySql).toString();
	}
	
//	public static void main(String[] args) {
//		String sql = "select idselect as 'id \\'sele\\\\'ct a', email as 'email \\'sele\\\\'ct a', username as user,password as froaa from user as u where user.id = (select id as user.id from user)";
//		SimpleSelectAsParser parser = new SimpleSelectAsParser(sql);
//
//		System.out.println(parser.toString());
//	}
}
